home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / news / readers / nn / nn6.4.patch7 < prev    next >
Encoding:
Text File  |  1990-07-09  |  56.2 KB  |  2,182 lines

  1.          This is an official patch to nn release 6.4
  2.          -------------------------------------------
  3.  
  4.                    PATCH #7
  5.  
  6.                 Priority: LOW
  7.  
  8.  
  9. These patches fix a few minor bugs in the 6.4 release, and add some
  10. new features based on patches and suggestions sent to me.
  11.  
  12. Specifically, it fixes a bug introduced in patch #6 with the new
  13. reading mode prompt style, where the array holding the prompt could be
  14. too small causing undefined behaviour (include core dumps).
  15.  
  16. Major new features are:
  17.  
  18. - User defined keymaps which can be bound to "prefix" keys, e.g.
  19.  
  20.     make map ctl-x            # create a new keymap named ctl-x
  21.     map both ^X prefix ctl-x    # bind it to ^X
  22.     map ctl-x x macro 1        # bind macro 1 to ^X x
  23.  
  24. - Printed and saved headers can now be fully costumized just like the
  25.   reading mode headers via two new variables: print-header-lines and
  26.   save-header-lines which use the same syntax as the header-lines
  27.   variable.
  28.  
  29. - On colour displays, overlapping text when scrolling through an
  30.   article in reading mode can now be "shaded" using any colour or
  31.   other display attribute you like, e.g.
  32.   
  33.     on term ti924-colour
  34.         set shading-on  ^[ [ 3 2 m
  35.         set shading-off ^[ [ 3 7 m
  36.         set mark-overlap-shading
  37.         unset mark-overlap
  38.     end
  39.     
  40. As usual, all changes are described in the updated RELEASE_NOTES file
  41. (read that for more details about this patch).  Thanks to all who
  42. reported bugs and provided fixes.
  43.  
  44. To apply this patch, use nn's :patch command, or run this command from
  45. the shell in the root of the nn source tree:
  46.     patch -p0 < this-article
  47.  
  48.  
  49. ++Kim Storm
  50.  
  51. *** ./LAST/account.c    Mon Jun 25 15:46:36 1990
  52. --- account.c    Thu Jul  5 23:45:07 1990
  53. ***************
  54. *** 273,279 ****
  55.       putchar(NL);
  56.       }
  57.   
  58. !     printf("%-8.8s  %4ld.%02ld  %5d  %s  ",
  59.          ac->ac_user,
  60.          ac->ac_total/60, ac->ac_total%60,
  61.          ac->ac_quota,
  62. --- 273,279 ----
  63.       putchar(NL);
  64.       }
  65.   
  66. !     printf("%-8.8s  %4ld.%02ld  %5d  %-12.12s  ",
  67.          ac->ac_user,
  68.          ac->ac_total/60, ac->ac_total%60,
  69.          ac->ac_quota,
  70. *** ./LAST/aux.sh    Mon Jun 25 15:46:38 1990
  71. --- aux.sh    Tue Jul  3 11:17:53 1990
  72. ***************
  73. *** 29,34 ****
  74. --- 29,36 ----
  75.   #    MAILER_PIPE    [mailer-pipe-input]
  76.   #    DFLT_ANSW    [response-default-answer]
  77.   
  78. + CC=""
  79.   . ${HOME}/.nn/.param
  80.   
  81.   # first argument is operation to be performed:
  82. *** ./LAST/doc/PROBLEMS    Sat May  5 16:16:28 1990
  83. --- doc/PROBLEMS    Thu Jul  5 21:33:10 1990
  84. ***************
  85. *** 307,312 ****
  86. --- 307,318 ----
  87.   are stripped to 7 bits, but articles displayed on the screen can be
  88.   shown either in 7 or 8 bit mode via the data-bits variable.
  89.   
  90. + With patch #6 installed, nn does indeed support 8 bit input if
  91. + data-bits = 8.  However, the positions 0x80 through 0x9f are reserved
  92. + for internal use, so only the various ISO 8859/* character sets are
  93. + *fully* supported, while some PC code pages may overlay some national
  94. + characters with function keys.
  95.   
  96.                    MAIL RECORDS
  97.                    ------------
  98. *** ./LAST/doc/RELEASE_NOTES    Mon Jun 25 15:46:39 1990
  99. --- doc/RELEASE_NOTES    Mon Jul  9 16:57:35 1990
  100. ***************
  101. *** 883,889 ****
  102. --- 883,930 ----
  103.   From:    KFS
  104.   Fixed:    Patch #6 [account.c execute.c]
  105.   
  106. + Prog:    nn
  107. + Title:    Syntax error if MALLOC_GRAIN is defined
  108. + From:    olson%anchor.esd@sgi.com (Dave Olson) + fix
  109. + Fixed:    Patch #7 [nn.c]
  110. + Prog:    nn
  111. + Title:    May crash in reading mode if prompt is too long
  112. + From:    root@ttank.ttank.com (Karl Bunch)
  113. + Fixed:    Patch #7 [more.c  (pr_fmt overflow)]
  114. + Prog:    nn
  115. + Title:    show-purpose-mode is ignored in auto-read-mode
  116. + From:    KFS
  117. + Fixed:    Patch #7 [menu.c]
  118. + Prog:    nn
  119. + Title:    All multi keys are named #A
  120. + From:    dean%coplex@relay.EU.net (Dean Brooks)
  121. + Fixed:    Patch #7 [keymap.c]
  122. + Prog:    aux
  123. + Title:    The CC variable conflicts with "standard" CC variable
  124. + From:    Greg Christy <greg@mickey.imsd.contel.com>
  125. +     scs@iti.org (Steve Simmons) +fix
  126. + Fixed:    Patch #7 [aux.sh]
  127. + Prog:    nnmaster expire - nntp
  128. + Title:    nnmaster terminates if nntp server is down when expire -E1 starts.
  129. + From:    pete@eleazar.dartmouth.edu (Pete Schmitt)
  130. + Fixed:    Patch #7 [nntp.c]
  131. + Prog:    nnacct
  132. + Title:    AUTHORIZE without ACCOUNTING does not work
  133. + From:    Peter J Nilsson <pjn@IDA.LiU.SE> + fix
  134. + Fixed:    Patch #7 [account.c proto.c]
  135.   
  136. + Prog:    nn
  137. + Title:    ~OLD~FOLDER~ is not removed when folder is compressed.
  138. + From:    conrad@zeno.mmwb.ucsf.EDU (Conrad Huang)
  139. + Fixed:    Patch #7 [folder.c]
  140.   New features since initial 6.4.0 release
  141.   ----------------------------------------
  142.   
  143. ***************
  144. *** 1052,1054 ****
  145. --- 1093,1137 ----
  146.   Title:    Header printed by :print now configurable via print-header-type
  147.   From:    KFS on request from Mikael.C.Kjaerulff@copenhagen.ncr.dk
  148.   Added:    Patch #6 [save.c variable.c nn.1]
  149. + Prog:    nn
  150. + Title:    Saved/printed short headers are now fully configureable
  151. +     via save-header-lines and print-header-lines variables.
  152. + From:    KFS on request from leo@aai.com
  153. + Added:    Patch #7 [save.c variable.c nn.1]
  154. + Prog:    nn
  155. + Title:    show-purpose-mode support on nntp clients.
  156. + From:    olson%anchor.esd@sgi.com (Dave Olson)
  157. + Added:    Patch #7 [nntp.c menu.c]
  158. + Prog:    nn
  159. + Title:    Overlap can now be "shaded" using "any" attribute (including colour)
  160. +     via the variables: mark-overlap-shading, shading-on, sharing-off
  161. + From:    KFS on request from Uwe Doering
  162. + Added:    Patch #7 [more.c variable.c nn.1]
  163. + Prog:    nn
  164. + Title:    Additional keymaps can now be created and bound to "prefix key".
  165. + From:    KFS on request from rock@Sun.COM (Bill "Rock" Petro)
  166. + Added:    Patch #7 [init.c keymap.c keymap.h menu.c more.c variable.c nn.1]
  167. +     set echo-prefix-key        # echo prefix key
  168. +     make map ctl-x            # create a new keymap named ctl-x
  169. +     map both ^X prefix ctl-x    # bind it to ^X
  170. +     map ctl-x x macro 1        # bind macro 1 to ^X x
  171. + Prog:    nn
  172. + Title:    Path: line is used in "From " line when use-path-in-from is set.
  173. + From:    KFS on request from Bill Gaines <gatech!iccdev!bill>
  174. + Added:    Patch #7 [save.c variable.c nn.1]
  175. + Prog:    nn
  176. + Title:    New "clear" command to clear screen (e.g. at top of init file)
  177. + From:     KFS on request from paul@uxc.cso.uiuc.edu (Paul Pomes)
  178. + Added:    Patch #7 [init.c]
  179. + Prog:    nn
  180. + Title:    New interactive :load command to reload init file (sequence is ignored)
  181. + From:    KFS
  182. + Added:    Patch #7 [init.c]
  183. *** ./LAST/folder.c    Mon Jun 25 15:46:40 1990
  184. --- folder.c    Mon Jul  9 14:51:12 1990
  185. ***************
  186. *** 464,469 ****
  187. --- 464,470 ----
  188.       fclose(dst);
  189.       goto move_back;
  190.       }
  191. +     unlink(oldfile);
  192.       return;
  193.   
  194.   move_back:
  195. *** ./LAST/group.c    Mon Jun 25 15:46:41 1990
  196. --- group.c    Thu Jul  5 18:06:18 1990
  197. ***************
  198. *** 381,386 ****
  199. --- 381,388 ----
  200.       if ((re = regcomp(name)) == NULL) return NULL;
  201.       y = any = 0;
  202.       
  203. +     if (pr && (flag & 1)) m_advinput();
  204.       if (flag & 1)
  205.       Loop_Groups_Sequence(gh) {
  206.           if (gh->last_db_article == 0) continue;
  207. *** ./LAST/init.c    Mon Jun 25 15:46:42 1990
  208. --- init.c    Mon Jul  9 17:10:35 1990
  209. ***************
  210. *** 238,251 ****
  211.       "decode",            6,    0,
  212.       "define",            6,    0,
  213.       "help",            4,    2,
  214.       "local",            5,    3,
  215.       "man",            3,    0,
  216. !     "map",            3,    -1,
  217. !     "map #",            5,    -2,
  218. !     "map both",            8,    4,
  219. !     "map key",            7,    0,
  220. !     "map menu",            8,    4,
  221. !     "map show",            8,    4,
  222.       "mkdir",            5,    1,
  223.       "patch",            5,    0, /* QUICK HACK */
  224.       "post",            4,    0, /* QUICK HACK */
  225. --- 238,249 ----
  226.       "decode",            6,    0,
  227.       "define",            6,    0,
  228.       "help",            4,    2,
  229. +     "load",            4,    0,
  230.       "local",            5,    3,
  231. +     "make",            4,    -1,
  232. +     "make map ",        9,    -2,
  233.       "man",            3,    0,
  234. !     "map",            3,    4,
  235.       "mkdir",            5,    1,
  236.       "patch",            5,    0, /* QUICK HACK */
  237.       "post",            4,    0, /* QUICK HACK */
  238. ***************
  239. *** 291,296 ****
  240. --- 289,295 ----
  241.       int temp;
  242.       register char *p, *q;
  243.       extern int file_completion(), var_completion(), cmd_completion();
  244. +     extern int keymap_completion();
  245.       extern int list_offset;
  246.   
  247.       if (other_compl) {
  248. ***************
  249. *** 369,380 ****
  250.               head = p;
  251.               temp++;
  252.               }
  253. !         if (temp != 1) return -1;
  254.   
  255. -         other_compl = cmd_completion;
  256.           tail = NULL;
  257.           len = p - head;
  258. !         temp = cmd_completion(head, len);
  259.           break;
  260.           }
  261.           if (temp <= 0) other_compl = NULL;
  262. --- 368,383 ----
  263.               head = p;
  264.               temp++;
  265.               }
  266. !         if (temp == 0) 
  267. !             other_compl = keymap_completion;
  268. !         else if (temp == 2)
  269. !             other_compl = cmd_completion;
  270. !         else
  271. !             return -1;
  272.   
  273.           tail = NULL;
  274.           len = p - head;
  275. !         temp = CALL(other_compl)(head, len);
  276.           break;
  277.           }
  278.           if (temp <= 0) other_compl = NULL;
  279. ***************
  280. *** 565,580 ****
  281.               dump_global_map();
  282.               break;
  283.           }
  284. !         CASE( "menu" ) {
  285. !             clrdisp();
  286. !             dump_key_map(menu_key_map, "menu", K_ONLY_MENU);
  287. !             break;
  288. !         }
  289. !         CASE( "show" ) {
  290. !             clrdisp();
  291. !             dump_key_map(more_key_map, "show", K_ONLY_MORE);
  292.               break;
  293. -         }
  294.   
  295.           init_message("unknown map '%s'", argv(mode_arg));
  296.           goto err;
  297. --- 568,575 ----
  298.               dump_global_map();
  299.               break;
  300.           }
  301. !         if (dump_key_map(name) >= 0)
  302.               break;
  303.   
  304.           init_message("unknown map '%s'", argv(mode_arg));
  305.           goto err;
  306. ***************
  307. *** 629,744 ****
  308.   {
  309.       int code, map_menu, map_show, must_redraw = 0;
  310.       key_type bind_to;
  311. !     SWITCH( argv(1) ) {
  312. !     CASE( "key" ) {
  313. !         if (argv(3) == NULL) break;
  314. !         global_key_map[parse_key(argv(2))] = parse_key(argv(3));
  315. !         goto out;
  316.       }
  317. !     if (argv(1)[0] == '#') {
  318. !         key_type multi_buffer[16], *mb;
  319. !         int i;
  320. !         if (argv(1)[1] == NUL) break;
  321. !         if (isdigit(argv(1)[1])) 
  322. !         bind_to = K_function(argv(1)[1] - '0');
  323. !         else {
  324. !         bind_to = parse_key(argv(1) + 1);
  325. !         if (bind_to < K_up_arrow || bind_to > K_right_arrow) break;
  326. !         }
  327. !         for (i = 2, mb = multi_buffer; argv(i); i++)
  328. !         *mb++ = parse_key(argv(i));
  329. !         *mb = NUL;
  330. !         enter_multi_key(bind_to, (key_type *)copy_str((char *)multi_buffer));
  331. !         goto out;
  332.       }
  333. !     code = K_UNBOUND;
  334. !     map_menu = map_show = 0;
  335. !     CASE( "menu" ) {
  336. !         map_menu++;
  337. !     }
  338. !     CASE( "show" ) {
  339. !         map_show++;
  340. !     }
  341. !     CASE( "both" ) {
  342. !         map_menu++;
  343. !         map_show++;
  344. !     }
  345. !     if (ARG(3, "(")) {
  346. !         extern char *m_define();
  347. !         code = (int)m_define("-2", initf);
  348. !         must_redraw = 1;
  349. !         if (code == K_UNBOUND) goto mac_err;
  350. !     }
  351. !     if (map_menu) {
  352. !         if (code == K_UNBOUND && argv(3))
  353. !         code = lookup_command(argv(3), K_ONLY_MENU);
  354. !         if (code == K_EQUAL_KEY) {
  355. !         if (argv(4))
  356. !             code = menu_key_map[parse_key(argv(4))];
  357. !         else
  358. !             goto mac_err;
  359. !         } else
  360. !         if (code == K_MACRO || code == K_ARTICLE_ID)
  361. !         if (argv(4))
  362. !             code |= atoi(argv(4));
  363. !         else
  364. !             goto mac_err;
  365. !         if (code != K_INVALID) {
  366. !         bind_to = parse_key(argv(2));
  367. !         if (code & K_MACRO && orig_menu_map[bind_to] == 0)
  368. !             orig_menu_map[bind_to] = menu_key_map[bind_to];
  369. !         menu_key_map[bind_to] = code;
  370. !         if (!map_show) goto out;
  371. !         }
  372. !     }
  373. !     if (map_show) {
  374. !         if (code == K_UNBOUND && argv(3))
  375. !         code = lookup_command(argv(3), K_ONLY_MORE);
  376. !         if (code == K_EQUAL_KEY) {
  377. !         if (argv(4))
  378. !             code = more_key_map[parse_key(argv(4))];
  379. !         else
  380. !             goto mac_err;
  381. !         } else
  382. !         if (code == K_MACRO)
  383. !         if (argv(4))
  384. !             code |= atoi(argv(4));
  385. !         else
  386. !             goto mac_err;
  387. !         if (code != K_INVALID) {
  388. !         more_key_map[parse_key(argv(2))] = code;
  389. !         goto out;
  390. !         }
  391. !     }
  392. !     if (argv(4)) break;
  393. !     if (code == K_INVALID) {
  394. !         init_message("unknown key command: %s", argv(3));
  395.           goto out;
  396.       }
  397.       }
  398. !     print_command("syntax error");
  399.       goto out;
  400.    mac_err:
  401.       print_command("map argument missing");
  402.    out:
  403. --- 624,727 ----
  404.   {
  405.       int code, map_menu, map_show, must_redraw = 0;
  406.       key_type bind_to;
  407. !     register struct key_map_def *map_def;
  408. !     register int *map;
  409. !     
  410. !     code = lookup_keymap(argv(1));
  411. !     if (code < 0) {
  412. !     print_command("unknown map");
  413. !     goto out;
  414. !     }
  415. !     map_def = &keymaps[code];
  416. !     
  417. !     if (map_def->km_flag & K_GLOBAL_KEY_MAP) {
  418. !     if (argv(3) == NULL) goto mac_err;
  419. !     if (argv(2) == NULL) {
  420. !         dump_global_map();
  421. !         return 1;
  422.       }
  423. !     global_key_map[parse_key(argv(2))] = parse_key(argv(3));
  424. !     return 0;
  425. !     }
  426. !     
  427. !     if (map_def->km_flag & K_MULTI_KEY_MAP) {
  428. !     key_type multi_buffer[16], *mb;
  429. !     int i;
  430. !     
  431. !     if (argv(1)[1] == NUL) {
  432. !         dump_multi_keys();
  433. !         return 1;
  434.       }
  435. !     
  436. !     if (isdigit(argv(1)[1])) 
  437. !         bind_to = K_function(argv(1)[1] - '0');
  438. !     else {
  439. !         bind_to = parse_key(argv(1) + 1);
  440. !         if (bind_to < K_up_arrow || bind_to > K_right_arrow) goto mac_err;
  441. !     }
  442. !     
  443. !     for (i = 2, mb = multi_buffer; argv(i); i++)
  444. !         *mb++ = parse_key(argv(i));
  445. !     *mb = NUL;
  446. !     
  447. !     enter_multi_key(bind_to, (key_type *)copy_str((char *)multi_buffer));
  448. !     return 0;
  449. !     }
  450. !     
  451. !     code = K_UNBOUND;
  452. !     map = map_def->km_map;
  453. !     map_show = map_def->km_flag & K_BOTH_MAPS;
  454. !     map_menu = map_def->km_flag & K_BIND_ORIG;
  455. !     
  456. !     if (ARG(3, "(")) {
  457. !     extern char *m_define();
  458. !     
  459. !     code = (int)m_define("-2", initf);
  460. !     must_redraw = 1;
  461. !     if (code == K_UNBOUND) goto mac_err;
  462. !     }
  463. !     
  464. !     if (code == K_UNBOUND && argv(3))
  465. !     code = lookup_command(argv(3), K_ONLY_MENU);
  466. !     
  467. !     switch (code) {
  468. !      case K_EQUAL_KEY:
  469. !     if (argv(4) == NULL) goto mac_err;
  470. !     code = map[parse_key(argv(4))];
  471. !     break;
  472. !     
  473. !      case K_MACRO:
  474. !      case K_ARTICLE_ID:
  475. !     if (argv(4) == NULL) goto mac_err;
  476. !     code |= atoi(argv(4));
  477. !     break;
  478. !     
  479. !      case K_PREFIX_KEY: 
  480. !     if (argv(4) == NULL) goto mac_err;
  481. !     code = lookup_keymap(argv(4));
  482. !     if (code < 0) {
  483. !         print_command("unknown prefix map");
  484.           goto out;
  485.       }
  486. +     code |= K_PREFIX_KEY;
  487. +     break;
  488.       }
  489. !     
  490. !     if (code == K_INVALID) {
  491. !     init_message("unknown key command: %s", argv(3));
  492. !     goto out;
  493. !     }
  494. !     
  495. !     bind_to = parse_key(argv(2));
  496. !     if (map_menu) {
  497. !     if (code & K_MACRO && orig_menu_map[bind_to] == 0)
  498. !         orig_menu_map[bind_to] = map[bind_to];
  499. !     }
  500. !     map[bind_to] = code;
  501. !     if (map_show)
  502. !     more_key_map[bind_to] = code;
  503.       goto out;
  504. !     
  505.    mac_err:
  506.       print_command("map argument missing");
  507.    out:
  508. ***************
  509. *** 946,951 ****
  510. --- 929,951 ----
  511.           break;
  512.       }
  513.   
  514. +     CASE("make") {
  515. +         if (ARG(1, "map") && argv(2)) {
  516. +         switch (make_keymap(argv(2))) {
  517. +          case -1:
  518. +             init_message("map %s already exists", argv(2));
  519. +             break;
  520. +          case -2:
  521. +             init_message("cannot make %s: too many maps", argv(2));
  522. +             break;
  523. +         }
  524. +         break;
  525. +         }
  526. +         print_command("invalid make command");
  527. +         break;
  528. +     }
  529.       CASE( "cd" ) {
  530.           if (change_dir(argv(1), in_init))
  531.           init_message("chdir %s FAILED", argv(1));
  532. ***************
  533. *** 953,958 ****
  534. --- 953,963 ----
  535.           break;
  536.       }
  537.   
  538. +     CASE( "clear" ) {
  539. +         clrdisp();
  540. +         break;
  541. +     }
  542.       if (in_init) {
  543.   
  544.           CASE( "load" ) {
  545. ***************
  546. *** 998,1003 ****
  547. --- 1003,1018 ----
  548.           }
  549.           return AC_KEYCMD;
  550.           }
  551. +     }
  552. +     CASE( "load" ) {
  553. +         clrdisp();
  554. +         in_init = 1;
  555. +         init_err = 0;
  556. +         load_init_file(argv(1) ? argv(1) : "init", (FILE **)NULL, 0);
  557. +         in_init = 0;
  558. +         if (init_err) any_key(0);
  559. +         return AC_REDRAW;
  560.       }
  561.   
  562.       CASE( "q" ) {
  563. *** ./LAST/keymap.c    Mon Jun 25 15:46:43 1990
  564. --- keymap.c    Thu Jul  5 19:09:32 1990
  565. ***************
  566. *** 503,508 ****
  567. --- 503,509 ----
  568.   
  569.       "patch",            K_PATCH,        0,
  570.       "post",            K_POST,            0,
  571. +     "prefix",            K_PREFIX_KEY,        0,
  572.       "preview",            K_PREVIEW,        0,
  573.       "previous",            K_PREVIOUS,        0,
  574.       "print",            K_PRINT,        0,
  575. ***************
  576. *** 536,542 ****
  577.   };
  578.   
  579.   static int name_map_size;
  580. ! static int max_cmd_name_length = 14;    /* recalculate if table is changed */
  581.   
  582.   export key_type global_key_map[KEY_MAP_SIZE];
  583.   
  584. --- 537,543 ----
  585.   };
  586.   
  587.   static int name_map_size;
  588. ! #define max_cmd_name_length 16    /* recalculate if table is changed */
  589.   
  590.   export key_type global_key_map[KEY_MAP_SIZE];
  591.   
  592. ***************
  593. *** 635,640 ****
  594. --- 636,642 ----
  595.       if (index > 0) break;
  596.       if (cmd->cmd_code == K_MACRO ||
  597.           cmd->cmd_code == K_ARTICLE_ID ||
  598. +         cmd->cmd_code == K_PREFIX_KEY ||
  599.           cmd->cmd_code == K_EQUAL_KEY)
  600.           sprintf(tail, "%s ", cmd->cmd_name + len);
  601.       else
  602. ***************
  603. *** 739,745 ****
  604.        default:
  605.           buf[0] = '#';
  606.           buf[1] = (c - K_function(0))
  607. !         + (c >= NORMAL_KEYS+ARROW_KEYS+MULTI_KEYS) ? 'A' : '0';
  608.           buf[2] = NUL;
  609.           goto out;
  610.       }
  611. --- 741,747 ----
  612.        default:
  613.           buf[0] = '#';
  614.           buf[1] = (c - K_function(0))
  615. !         + (c >= K_function(MULTI_KEYS) ? 'A'-K_function(MULTI_KEYS) : '0');
  616.           buf[2] = NUL;
  617.           goto out;
  618.       }
  619. ***************
  620. *** 793,807 ****
  621.   }
  622.   
  623.   
  624. ! dump_key_map(map, where, restriction)
  625. ! int map[];
  626.   char *where;
  627. - int restriction;
  628.   {
  629.       register struct command_name_map *cnmp;
  630.       register key_type c;
  631.       register int code, first_prt;
  632.       
  633.       clrdisp();
  634.       so_printf("\1KEY BINDINGS (%s)\1\n\n", where);
  635.   
  636. --- 795,812 ----
  637.   }
  638.   
  639.   
  640. ! dump_key_map(where)
  641.   char *where;
  642.   {
  643.       register struct command_name_map *cnmp;
  644.       register key_type c;
  645.       register int code, first_prt;
  646. +     int *map, restriction;
  647.       
  648. +     if ((code = lookup_keymap(where)) < 0) return -1;
  649. +     map = keymaps[code].km_map;
  650. +     restriction = keymaps[code].km_flag & (K_ONLY_MENU | K_ONLY_MORE);
  651.       clrdisp();
  652.       so_printf("\1KEY BINDINGS (%s)\1\n\n", where);
  653.   
  654. ***************
  655. *** 841,847 ****
  656. --- 846,948 ----
  657.           if (map == menu_key_map && orig_menu_map[c] != K_UNBOUND) 
  658.           printf(" (%s)", command_name(orig_menu_map[c]));
  659.       }
  660. +     else if (map[c] & K_PREFIX_KEY) {
  661. +         if (pg_next() < 0) goto out;
  662. +         printf("prefix %s: %s",
  663. +            keymaps[(map[c] & ~K_PREFIX_KEY)].km_name, key_name(c));
  664. +     }
  665.   
  666.    out:
  667.       pg_end();
  668. + }
  669. + #define MAX_KEYMAPS    17
  670. + struct key_map_def keymaps[MAX_KEYMAPS+1] = {
  671. +     "#",    NULL,        K_MULTI_KEY_MAP,
  672. +     "key",    NULL,        K_GLOBAL_KEY_MAP,
  673. +     "menu",    menu_key_map,    K_BIND_ORIG | K_ONLY_MENU,
  674. +     "show",    more_key_map,    K_ONLY_MORE,
  675. +     "both",    menu_key_map,    K_BOTH_MAPS | K_BIND_ORIG,
  676. +     "more",    more_key_map,    K_ONLY_MORE,
  677. +     "read",    more_key_map,    K_ONLY_MORE,
  678. +     NULL,
  679. + };
  680. + lookup_keymap(name)
  681. + char *name;
  682. + {
  683. +     register struct key_map_def *m;
  684. +     
  685. +     if (name[0] == '#') return 0;
  686. +     
  687. +     for (m = keymaps; m->km_name; m++) {
  688. +     if (strcmp(name, m->km_name) == 0) return m - keymaps;
  689. +     }
  690. +     return keymaps - m;
  691. + }
  692. + make_keymap(name)
  693. + char *name;
  694. + {
  695. +     register struct key_map_def *m;
  696. +     register int *kp;
  697. +     int ix;
  698. +     
  699. +     ix = lookup_keymap(name);
  700. +     if (ix >= 0) return -1;
  701. +     ix = -ix;
  702. +     if (ix == MAX_KEYMAPS) return -2;
  703. +     
  704. +     m = &keymaps[ix];
  705. +     m->km_name = copy_str(name);
  706. +     m->km_map = newobj(int, KEY_MAP_SIZE);
  707. +     m->km_flag = 0;
  708. +     for (kp = m->km_map; kp < &(m->km_map)[KEY_MAP_SIZE]; ) *kp++ = K_UNBOUND;
  709. +     return ix;
  710. + }
  711. + keymap_completion(buf, ix)
  712. + char *buf;
  713. + int ix;
  714. + {
  715. +     static char *head, *tail = NULL;
  716. +     static int len;
  717. +     static struct key_map_def *map, *help_map;
  718. +     if (ix < 0) return 0;
  719. +     if (buf) {
  720. +     head = buf;
  721. +     tail = buf + ix;
  722. +     while (*head && isspace(*head)) head++;
  723. +     help_map = map = keymaps;
  724. +     len = tail - head;
  725. +     return 1;
  726. +     }
  727. +     if (ix) {
  728. +     list_completion((char *)NULL);
  729. +     if (help_map->km_name == NULL)
  730. +         help_map = keymaps;
  731. +     for (;help_map->km_name; help_map++) {
  732. +         if (strncmp(help_map->km_name, head, len)) continue;
  733. +         if (list_completion(help_map->km_name) == 0) break;
  734. +     }
  735. +     fl;
  736. +     return 1;
  737. +     }
  738. +     for (; map->km_name; map++) {
  739. +     if (len && strncmp(map->km_name, head, len)) continue;
  740. +     strcpy(tail, map->km_name + len);
  741. +     if (map != keymaps) strcat(tail, " ");
  742. +     map++;
  743. +     return 1;
  744. +     }
  745. +     return 0;
  746.   }
  747. *** ./LAST/keymap.h    Mon Jun 25 15:46:43 1990
  748. --- keymap.h    Thu Jul  5 17:29:40 1990
  749. ***************
  750. *** 103,108 ****
  751. --- 103,109 ----
  752.   
  753.   #define    K_MACRO            0x0100 /* call macro            */
  754.   #define    K_ARTICLE_ID        0x0200 /* article id in lower part    */
  755. + #define K_PREFIX_KEY        0x0400 /* key map number in lower part    */
  756.   
  757.   /* keymap definitions from keymap.c */
  758.   
  759. ***************
  760. *** 112,117 ****
  761. --- 113,122 ----
  762.   
  763.   #define K_ONLY_MENU    0x0001
  764.   #define K_ONLY_MORE    0x0002
  765. + #define    K_BOTH_MAPS    0x0004    /* map flag: for "both" */
  766. + #define    K_BIND_ORIG    0x0008    /* map flag: must maintain orig_menu_map */
  767. + #define K_GLOBAL_KEY_MAP    0x0010    /* "key" */
  768. + #define    K_MULTI_KEY_MAP        0x0020     /* "#..." */
  769.   
  770.   typedef unsigned char key_type;
  771.   
  772. ***************
  773. *** 123,125 ****
  774. --- 128,139 ----
  775.   
  776.   extern char *key_name();
  777.   extern key_type parse_key();
  778. + struct key_map_def {
  779. +     char    *km_name;    /* key map name */
  780. +     int        *km_map;    /* key map table */
  781. +     
  782. +     int        km_flag;    /* flags */
  783. + };
  784. + extern struct key_map_def keymaps[];
  785. *** ./LAST/macro.c    Mon Jun 25 15:46:43 1990
  786. --- macro.c    Fri Jun 29 23:46:47 1990
  787. ***************
  788. *** 453,458 ****
  789. --- 453,460 ----
  790.   
  791.       if (m_level == 0)
  792.       no_advance = 0;
  793. +     else if (m == NULL)
  794. +     m_level--;
  795.       else {
  796.       if (m_level > MSTACK) {
  797.           msg("Macro stack overflow");
  798. *** ./LAST/man/nn.1.B    Mon Jun 25 15:46:45 1990
  799. --- man/nn.1.B    Mon Jul  9 17:17:28 1990
  800. ***************
  801. *** 741,746 ****
  802. --- 741,751 ----
  803.   Change current working directory.  If the directory argument is not provided,
  804.   \fInn\fP will prompt for it.
  805.   .TP
  806. + \fB:clear\fP
  807. + Clear the screen (without redraw).  This may be useful at the
  808. + beginning of the init file (possibly guarded by "on program nn"), or
  809. + in some macros.
  810. + .TP
  811.   \fB:compile\fP
  812.   Recompile the \fIkill\fP file.  This is not necessary under normal
  813.   operation since \fInn\fP automatically compiles the file on start-up
  814. ***************
  815. *** 761,766 ****
  816. --- 766,776 ----
  817.   \fB:help\fP [ \fIsubject\fP ]
  818.   Provide online help on the specified subject.  If you omit the
  819.   subject, a list of the available topics will be given.
  820. + .TP
  821. + \fB:load\fP [ \fIfile\fP ]
  822. + Load the specified \fIfile\fP.  If the \fIfile\fP argument is omitted,
  823. + the init file is reloaded.
  824. + The \fBsequence\fP part (if present) is ignored.
  825.   .TP
  826.   \fB:local\fP \fIvariable\fP [ \fIvalue\fP ]
  827.   Make the variable local to the current group.  Subsequent changes to
  828. *** ./LAST/man/nn.1.C    Mon Jun 25 15:46:46 1990
  829. --- man/nn.1.C    Mon Jul  9 17:17:28 1990
  830. ***************
  831. *** 377,382 ****
  832. --- 377,387 ----
  833.   \fInn\fP will prompt for another extended command instead of redrawing
  834.   the screen (hit \fBreturn\fP to redraw).
  835.   .TP
  836. + \fBecho-prefix-key\fP        (boolean, default true)
  837. + When true, hitting a prefix key (see the section on key mapping below)
  838. + will cause the prefix key to be echoed in the message line to indicate
  839. + that another key is expected.
  840. + .TP
  841.   \fBedit-patch-command\fP    (boolean, default true)
  842.   When true, the \fB:patch\fP command will show the current
  843.   \fBpatch-command\fP and give you a chance to edit it before applying
  844. ***************
  845. *** 631,636 ****
  846. --- 636,648 ----
  847.   of the terminal if possible) to indicate the end of the overlap (see the
  848.   \fBoverlap\fP variable).
  849.   .TP
  850. + \fBmark-overlap-shading\fP    (boolean, default false)
  851. + When set, \fInn\fP will \fIshade\fP overlapping lines (see the
  852. + \fBoverlap\fP variable) using the attributes defined by the
  853. + \fBshading-on\fP and \fBshading-off\fP variables (of if not set, with
  854. + the underline attribute).  This is typically used to give overlapping
  855. + lines a different colour on terminals which have this capability.
  856. + .TP
  857.   \fBmessage-history\fP \fIN\fP    (integer, default 15)
  858.   Specifies the maximum number, \fIN\fP, of older messages which can be
  859.   recalled with the \fB^P\fP {\fBmessage\fP} command.
  860. ***************
  861. *** 781,786 ****
  862. --- 793,805 ----
  863.   \fBpreview-mark-read\fP        (boolean, default true)
  864.   When set, previewing an article will mark the article as read.
  865.   .TP
  866. + \fBprint-header-lines\fP \fIfields\fP    (string, default "FDGS")
  867. + Specifies the list of header fields that are output when
  868. + an article is printed via the \fB:print\fP command and
  869. + \fBprint-header-type\fP is 1 (short header).  The \fIfields\fP 
  870. + specification is desctribed
  871. + in the section on Customized Article Headers below.
  872. + .TP
  873.   \fBprint-header-type\fP \fIN\fP    (integer, default 1)
  874.   Specifies what kind of header is printed by the \fB:print\fP command,
  875.   corresponding to the three \fBsave-*\fP commands: \fI0\fP prints only
  876. ***************
  877. *** 882,887 ****
  878. --- 901,912 ----
  879.   substitute the \fI*\fP with successive numbers starting from one.
  880.   Setting this variable will cause these numbers to start from \fIN\fP+1.
  881.   .TP
  882. + \fBsave-header-lines\fP \fIfields\fP    (string, default "FDNS")
  883. + Specifies the list of header fields that are saved when
  884. + an article is saved via the \fBO\fP {\fBsave-short\fP} command.
  885. + The \fIfields\fP specification is desctribed
  886. + in the section on Customized Article Headers below.
  887. + .TP
  888.   \fBsave-report\fP    (boolean, default true)
  889.   When set, a message reporting the number of lines written is shown
  890.   after saving an article.  Since messages are shown for a few seconds,
  891. ***************
  892. *** 902,907 ****
  893. --- 927,952 ----
  894.   Specifies whether the \fBfind\fP (=) command in article selection mode
  895.   will match on the subject or the sender.
  896.   .TP
  897. + \fBshading-on\fP \fIcode\fP...    (control string, default not set)
  898. + Specifies the escape code to be sent to the terminal to cause
  899. + "shading" of the following output to the screen.  This is used if the
  900. + \fBmark-overlap-shading\fP is set, and by the `+' attribute in the
  901. + \fBheader-lines\fP variable.
  902. + .TP
  903. + \fBshading-off\fP \fIcode\fP...    (control string, default not set)
  904. + Specifies the escape code to be sent to the terminal to turn off the
  905. + shading defined by \fBshading-on\fP.  Shading will typically
  906. + be done by changing the foreground colour to change, e.g.
  907. + .sp 0.5v
  908. + .nf
  909. +     on term ti924-colour
  910. +         set shading-on  ^[ [ 3 2 m
  911. +         set shading-off ^[ [ 3 7 m
  912. +         set mark-overlap-shading
  913. +         unset mark-overlap
  914. +     end
  915. + .fi
  916. + .TP
  917.   \fBshell\fP \fIprogram\fP    (string, default $SHELL)
  918.   The shell program used to execute shell escapes.
  919.   .TP
  920. ***************
  921. *** 1078,1083 ****
  922. --- 1123,1138 ----
  923.   Specifies how many changes need to be done to the .newsrc or select
  924.   files before they are written back to disk.  The default setting
  925.   causes .newsrc to be updated every time a group has been read.
  926. + .TP
  927. + \fBuse-path-in-from\fP        (boolean, default false)
  928. + When \fBmail-format\fP is set, saved articles will be preceded by a
  929. + specially formatted \&"From\ " line:
  930. + .br
  931. +     From origin date
  932. + .br
  933. + Normally, the origin will be the name of the news group where the
  934. + article appeared, but if \fBuse-path-in-from\fP is set, the contents
  935. + of the "Path:" header will be used as the origin.
  936.   .TP
  937.   \fBuse-selections\fP        (boolean, default true)
  938.   When set, \fInn\fP uses the selections and other article attributes
  939. *** ./LAST/man/nn.1.D    Mon Jun 25 15:46:47 1990
  940. --- man/nn.1.D    Mon Jul  9 17:17:28 1990
  941. ***************
  942. *** 15,23 ****
  943.   customized headers will then contain exactly these header lines
  944.   \fIin the specified order\fP.
  945.   .LP
  946.   The following header line identifiers are recognized in the
  947. ! .B header-lines
  948. ! variable:
  949.   .LP
  950.   .in +8n
  951.   .ta 5m
  952. --- 15,28 ----
  953.   customized headers will then contain exactly these header lines
  954.   \fIin the specified order\fP.
  955.   .LP
  956. + The same specifications are also used by the \fB:print\fP and
  957. + \fBsave-short\fP commands via the \fBprint-header-lines\fP and
  958. + \fBsave-header-lines\fP variables.
  959. + .LP
  960.   The following header line identifiers are recognized in the
  961. ! \fBheader-lines\fP,
  962. ! \fBprint-header-lines\fP, 
  963. ! and \fBsave-header-lines\fP variables:
  964.   .LP
  965.   .in +8n
  966.   .ta 5m
  967. ***************
  968. *** 25,30 ****
  969. --- 30,37 ----
  970.   .br
  971.   \fBA\fP    Approved:
  972.   .br
  973. + \fBa\fP    Spool-File:    (path of spool file containing the article)
  974. + .br
  975.   \fBB\fP    Distribution:
  976.   .br
  977.   \fBD\fP    Date:
  978. ***************
  979. *** 55,60 ****
  980. --- 62,69 ----
  981.   .br
  982.   \fBS\fP    Subject:
  983.   .br
  984. + \fBv\fP    Save-File:    (the default save file for this article)
  985. + .br
  986.   \fBW\fP    Followup-To:
  987.   .br
  988.   \fBX\fP    References:
  989. ***************
  990. *** 65,73 ****
  991. --- 74,95 ----
  992.   .in -8n
  993.   .DT
  994.   .LP
  995. + The 'G' and 'g' fields will include the local article number if it is
  996. + known, e.g.
  997. + .br
  998. +     Newsgroup: news.software.nn/754
  999. + .LP
  1000. + The following special symbols are recognized in the \fBheader-lines\fP
  1001. + variable (and ignored otherwise):
  1002. + .LP
  1003.   Preceding the identifier with an equal sign "=" or an underscore "_"
  1004.   will cause the header field contents to be high-lighted or underlined.
  1005.   .LP
  1006. + A plus sign "+" will use the shading attribute defined by
  1007. + \fBshading-on\fP and \fBshading-off\fP to high-light the field
  1008. + contents.  If no shading attribute is defined it will underline the
  1009. + field instead.
  1010. + .LP
  1011.   Including an asterisk "*" in the list will produce the standard one
  1012.   line header at that point.
  1013.   .LP
  1014. ***************
  1015. *** 494,499 ****
  1016. --- 516,550 ----
  1017.   in reading mode is:
  1018.   .sp 0.5v
  1019.       \fBmap show\fP \fIkey command\fP
  1020. + .LP
  1021. + In addition to the direct mappings described above, the following
  1022. + variations of the \fBmap\fP command are available:
  1023. + .TP
  1024. + .B User defined keymaps
  1025. + Additional keymaps can be defined using the command
  1026. + .sp 0.5v
  1027. +     \fBmake map\fP \fInewmap\fP
  1028. + .sp 0.5v
  1029. + This will create a new keymap which can initialized using normal
  1030. + \fBmap\fP commands, e.g.
  1031. + .sp 0.5v
  1032. +     \fBmap\fP \fInewmap key command\fP 
  1033. + .sp 0.5v
  1034. + To activate a user-defined keymap, it must be bound to a \fIprefix key\fP:
  1035. + .sp 0.5v
  1036. +     \fBmap\fP \fIbase-map prefix-key\fP \fBprefix\fP \fInewmap\fP
  1037. + .sp 0.5v
  1038. + When used, the prefix key itself does not activate a command, but
  1039. + instead it require another key to be entered and then execute the
  1040. + command bound to that key in the keymap which is bound to the prefix key.
  1041. +   For example, to let the key sequence "^X i" execute macro number 10 in
  1042. + both modes, the following commands can be used:
  1043. + .sp 0.5v
  1044. + .nf
  1045. +     make map ctl-x
  1046. +     map ctl-x i macro 10
  1047. +     map both ^X prefix ctl-x
  1048. + .fi
  1049.   .TP
  1050.   .B Mapping keys in both modes
  1051.   Using the pseudo-keymap `both', it is possible to map a key to a
  1052. *** ./LAST/master.c    Mon Jun 25 15:46:48 1990
  1053. --- master.c    Fri Jul  6 01:57:35 1990
  1054. ***************
  1055. *** 730,736 ****
  1056.   #endif
  1057.           if (debug_mode) {
  1058.           printf("NONE (*** SLEEP ***)\n");
  1059. -         continue;
  1060.           }
  1061.   
  1062.           if (trace) log_entry('T', "none");
  1063. --- 730,735 ----
  1064. ***************
  1065. *** 753,759 ****
  1066.   #ifdef NNTP
  1067.       if (use_nntp) nntp_cleanup();
  1068.   #endif
  1069. !     if (!debug_mode) sleep(repeat_delay);
  1070.       if (s_hangup) break;
  1071.       }
  1072.   
  1073. --- 752,758 ----
  1074.   #ifdef NNTP
  1075.       if (use_nntp) nntp_cleanup();
  1076.   #endif
  1077. !     sleep(repeat_delay);
  1078.       if (s_hangup) break;
  1079.       }
  1080.   
  1081. *** ./LAST/menu.c    Mon Jun 25 15:46:49 1990
  1082. --- menu.c    Thu Jul  5 17:53:17 1990
  1083. ***************
  1084. *** 13,18 ****
  1085. --- 13,19 ----
  1086.   
  1087.   import char *news_lib_directory;
  1088.   
  1089. + export int  echo_prefix_key = 1; /* echo prefix keys */
  1090.   export int  preview_window = 0;    /* size of preview window */
  1091.   export int  fmt_linenum    = 1; /* menu line format */
  1092.   export int  fmt_rptsubj    = 0; /* repeat identical subjects if !0 */
  1093. ***************
  1094. *** 498,503 ****
  1095. --- 499,505 ----
  1096.   {
  1097.       extern int any_message;
  1098.       register int c, map;
  1099. +     int *key_map = menu_key_map;
  1100.   
  1101.       if (flush_typeahead) flush_input();
  1102.   
  1103. ***************
  1104. *** 510,519 ****
  1105.       map = c & ~GETC_COMMAND;
  1106.       } else {
  1107.       cur_key = c;
  1108. !     map = menu_key_map[c];
  1109.       }
  1110.       if (s_hangup) map = K_QUIT;
  1111.   
  1112.       if (map & K_ARTICLE_ID) {
  1113.       article_id = map & ~K_ARTICLE_ID;
  1114.       map = K_ARTICLE_ID;
  1115. --- 512,527 ----
  1116.       map = c & ~GETC_COMMAND;
  1117.       } else {
  1118.       cur_key = c;
  1119. !     map = key_map[c];
  1120.       }
  1121.       if (s_hangup) map = K_QUIT;
  1122.   
  1123. +     if (map & K_PREFIX_KEY) {
  1124. +     key_map = keymaps[map & ~K_PREFIX_KEY].km_map;
  1125. +     if (echo_prefix_key) msg("%s", key_name(cur_key));
  1126. +     goto loop;
  1127. +     }
  1128.       if (map & K_ARTICLE_ID) {
  1129.       article_id = map & ~K_ARTICLE_ID;
  1130.       map = K_ARTICLE_ID;
  1131. ***************
  1132. *** 598,614 ****
  1133.   static get_purpose(purpose)
  1134.   char *purpose;
  1135.   {
  1136. ! #ifdef NNTP
  1137. !     return;            /* newsgroups file is not available */
  1138. ! #else
  1139. !     FILE *f;
  1140.       char line[256], group[80];
  1141.       register char *cp, *pp;
  1142.       register int len;
  1143.   
  1144. !     f = open_file(relative(news_lib_directory, "newsgroups"), OPEN_READ);
  1145. !     if (f == NULL) return;
  1146.       sprintf(group, "%s\t", current_group->group_name);
  1147.       len = current_group->group_name_length + 1;
  1148.   
  1149. --- 606,631 ----
  1150.   static get_purpose(purpose)
  1151.   char *purpose;
  1152.   {
  1153. !     static FILE *f = NULL;
  1154. !     static not_avail = 0;
  1155.       char line[256], group[80];
  1156.       register char *cp, *pp;
  1157.       register int len;
  1158.   
  1159. !     if (not_avail) return;
  1160. ! #ifdef NNTP
  1161. !     if (use_nntp) {
  1162. !     extern FILE *nntp_get_newsgroups();
  1163. !     f = nntp_get_newsgroups();
  1164. !     } else
  1165. ! #endif
  1166. !     f = open_file(relative(news_lib_directory, "newsgroups"), OPEN_READ);
  1167. !     if (f == NULL) {
  1168. !     not_avail = 1;
  1169. !     return;
  1170. !     }
  1171. !     rewind(f);
  1172. !     
  1173.       sprintf(group, "%s\t", current_group->group_name);
  1174.       len = current_group->group_name_length + 1;
  1175.   
  1176. ***************
  1177. *** 620,628 ****
  1178.           *pp++ = *cp++;
  1179.       *pp = NUL;
  1180.       }
  1181. -     fclose(f);
  1182. - #endif
  1183.   }
  1184.   
  1185.   
  1186. --- 637,642 ----
  1187. ***************
  1188. *** 736,741 ****
  1189. --- 750,758 ----
  1190.       auto_read = entry_check = 0;
  1191.       if (repl_attr_all(0, A_AUTO_SELECT, 0)) {
  1192.           k_cmd = K_READ_GROUP_UPDATE;
  1193. +         if (purpose[0])
  1194. +         strcpy(delayed_msg, purpose);
  1195. +         else
  1196.           sprintf(delayed_msg, "Entering %s, %ld articles",
  1197.               current_group->group_name, (long)n_articles);
  1198.           goto do_auto_read;
  1199. *** ./LAST/more.c    Mon Jun 25 15:46:49 1990
  1200. --- more.c    Sat Jul  7 01:35:47 1990
  1201. ***************
  1202. *** 32,37 ****
  1203. --- 32,38 ----
  1204.   import int  auto_preview_mode;
  1205.   import int  flush_typeahead;
  1206.   import int  case_fold_search;
  1207. + import int  echo_prefix_key;
  1208.   
  1209.   import char delayed_msg[];
  1210.   
  1211. ***************
  1212. *** 48,53 ****
  1213. --- 49,67 ----
  1214.   
  1215.   #define LINEMAX    100        /* most articles are less than 100 lines */
  1216.   
  1217. + export int  mark_overlap_shading = 0;
  1218. + export char *shade_on_attr = NULL;
  1219. + export char *shade_off_attr = NULL;
  1220. + static shadeline(on)
  1221. + int on;
  1222. + {
  1223. +     if (on) {
  1224. +     if (shade_on_attr) fputs(shade_on_attr, stdout); else underline(1);
  1225. +     } else
  1226. +     if (shade_off_attr) fputs(shade_off_attr, stdout); else underline(0);
  1227. + }
  1228. +     
  1229.   static struct header_def {
  1230.       char field;
  1231.       char *text;
  1232. ***************
  1233. *** 74,82 ****
  1234. --- 88,209 ----
  1235.       'G', "Newsgroup",    &news.ng_groups,    0,
  1236.       'n', "Newsgroups",    &news.ng_groups,    0,
  1237.       'x', "Back-Ref",    &news.ng_bref,        0,
  1238. +     'v', "Save-File",    NULL,            0,
  1239. +     'a', "Spool-File",    NULL,            0,
  1240.       0
  1241.   };
  1242.   
  1243. + get_header_field(code, namep, valp, ah)
  1244. + char code, **namep, **valp;
  1245. + register article_header *ah;
  1246. + {
  1247. +     static char special[FILENAME];
  1248. +     register struct header_def *hdef;
  1249. +     import char *folder_save_file, *default_save_file;
  1250. +     char *lp;
  1251. +     lp = NULL;
  1252. +     for (hdef = header_defs; hdef->field; hdef++) {
  1253. +     if (hdef->field != code) continue;
  1254. +     if ((ah->flag & A_DIGEST) && hdef->digest)
  1255. +         lp = *(hdef->digest);
  1256. +     if (lp == NULL && hdef->news)
  1257. +         lp = *(hdef->news);
  1258. +     break;
  1259. +     }
  1260. +     
  1261. +     switch (code) {
  1262. +      case 'n':
  1263. +      case 'g':
  1264. +     if (lp == NULL) break;
  1265. +     if (!(current_group->group_flag & G_MERGED) && strchr(lp, ',') == NULL)
  1266. +         return 0;
  1267. +     if (code == 'n') break;
  1268. +      case 'G':
  1269. +     if (ah->a_number > 0) {
  1270. +         sprintf(special, "%s/%ld", 
  1271. +             current_group->group_name, (long)ah->a_number);
  1272. +         lp = special;
  1273. +     } else
  1274. +         lp = current_group->group_name;
  1275. +     break;
  1276. +      case 'a':
  1277. +     if (current_group->group_flag & G_FOLDER)
  1278. +         lp = current_group->archive_file;
  1279. +     else
  1280. +     if (group_file_name && *group_file_name)
  1281. +         lp = group_path_name;
  1282. +     break;
  1283. +      case 'v':
  1284. +     if ((lp = current_group->save_file) == NULL)
  1285. +         lp = (current_group->group_flag & G_FOLDER) ?
  1286. +         folder_save_file : default_save_file;
  1287. +     if (lp == NULL) return 0;
  1288. +     if (expand_file_name(special, lp, 2)) lp = special;
  1289. +     break;
  1290. +     }
  1291. +     if (lp == NULL) return 0;
  1292. +     *namep = hdef->text;
  1293. +     *valp = lp;
  1294. +     return 1;
  1295. + }
  1296. + static char *scan_codes;
  1297. + static article_header *scan_arthdr;
  1298. + scan_header_fields(fields, ah)
  1299. + char *fields;
  1300. + article_header *ah;
  1301. + {
  1302. +     scan_codes = fields;
  1303. +     scan_arthdr = ah;
  1304. + }
  1305. + next_header_field(namep, valp, attrp)
  1306. + char **namep, **valp;
  1307. + fct_type *attrp;
  1308. + {
  1309. +     fct_type attr;
  1310. +     extern highlight(), underline();
  1311. +     while (*scan_codes) {
  1312. +     attr = NULL_FCT;
  1313. +     *namep = NULL;
  1314. +     switch (*scan_codes) {
  1315. +      case '*':
  1316. +         scan_codes++;
  1317. +         return 1;    /* name == NULL */
  1318. +         
  1319. +      case '=':
  1320. +         attr = highlight;
  1321. +         scan_codes++;
  1322. +         break;
  1323. +         
  1324. +      case '_':
  1325. +         attr = underline;
  1326. +         scan_codes++;
  1327. +         break;
  1328. +      case '+':
  1329. +         attr = shadeline;
  1330. +         scan_codes++;
  1331. +         break;
  1332. +     }
  1333. +     
  1334. +     if (*scan_codes == NUL) break;
  1335. +     if (attrp) *attrp = attr;
  1336. +     if (get_header_field(*scan_codes++, namep, valp, scan_arthdr))
  1337. +         return 1;
  1338. +     }
  1339. +     return 0;
  1340. + }
  1341.   static char *a_st_flags(flag)
  1342.   flag_type flag;
  1343.   {
  1344. ***************
  1345. *** 124,129 ****
  1346. --- 251,257 ----
  1347.   article_header *ah;
  1348.   int mode, screen_offset;
  1349.   {
  1350. +     register char *lp;
  1351.       register int c, col, lno;
  1352.       register FILE *art;
  1353.       int more_cmd, eof, skip_spaces, has_space, window_lines;
  1354. ***************
  1355. *** 132,138 ****
  1356.       off_t lineposbuf[LINEMAX];
  1357.       off_t *linepos = lineposbuf;
  1358.       int linemax = LINEMAX;
  1359. !     char linebuf[200], *lp, skip_char;
  1360.       int skip_wrap;
  1361.       news_header_buffer ngheader, dgheader;
  1362.       struct news_header news_save;
  1363. --- 260,266 ----
  1364.       off_t lineposbuf[LINEMAX];
  1365.       off_t *linepos = lineposbuf;
  1366.       int linemax = LINEMAX;
  1367. !     char linebuf[200], skip_char;
  1368.       int skip_wrap;
  1369.       news_header_buffer ngheader, dgheader;
  1370.       struct news_header news_save;
  1371. ***************
  1372. *** 145,152 ****
  1373.       article_header digestah;
  1374.       char *fname, *hdrline;
  1375.       extern STANDOUT;
  1376. !     char pr_fmt[60], send_date[40];
  1377. !     int match_expr;
  1378.       char *match_start, *match_end;
  1379.       int open_modes, hdr_mode, o_mode;
  1380.       struct header_def *hdef;
  1381. --- 273,283 ----
  1382.       article_header digestah;
  1383.       char *fname, *hdrline;
  1384.       extern STANDOUT;
  1385. !     char pr_fmt[200], send_date[40];
  1386. !     int match_expr, shade_overlap, shade_line;
  1387. !     int *key_map;
  1388. !     key_type cur_key;
  1389. !     fct_type hdrattr;
  1390.       char *match_start, *match_end;
  1391.       int open_modes, hdr_mode, o_mode;
  1392.       struct header_def *hdef;
  1393. ***************
  1394. *** 222,237 ****
  1395.       match_lines = match_redraw = match_expr = 0;
  1396.       underline_line = -1;
  1397.       fake_underline = 0;
  1398.   
  1399.       stop_line = first_page_lines ? first_page_lines : -1;
  1400.   
  1401.       if (new_read_prompt) {
  1402.       import long n_selected;
  1403.   
  1404.       if (mode & (MM_PREVIEW | MM_DIGEST) || n_selected == 0)
  1405.           sprintf(pr_fmt,
  1406.               "\1\2--%s-- %s%s %s--%%s--%%s\1",
  1407. !             current_group->group_name,
  1408.               (mode & MM_DIGEST) ? "DIGEST" :
  1409.               (mode & MM_PREVIEW) ? "PREVIEW" : "LAST",
  1410.               (ah->flag & A_NEXT_SAME) ? "+next" : "",
  1411. --- 353,384 ----
  1412.       match_lines = match_redraw = match_expr = 0;
  1413.       underline_line = -1;
  1414.       fake_underline = 0;
  1415. +     shade_overlap = 0;
  1416.   
  1417.       stop_line = first_page_lines ? first_page_lines : -1;
  1418.   
  1419.       if (new_read_prompt) {
  1420.       import long n_selected;
  1421. +     char *xp, *group_name = current_group->group_name;
  1422. +     int len, maxl;
  1423.   
  1424. +     maxl = novice ? 18 : 25;
  1425. +     
  1426. +     if ((len = strlen(group_name)) > maxl) {
  1427. +         for (xp = group_name + len - maxl; *xp; xp++) {
  1428. +         if (*xp == '.') break;
  1429. +         if (*xp == '/') { xp++; break; }
  1430. +         }
  1431. +         if (*xp)
  1432. +         group_name = xp;
  1433. +         else
  1434. +         group_name += len - maxl;
  1435. +     }
  1436. +     
  1437.       if (mode & (MM_PREVIEW | MM_DIGEST) || n_selected == 0)
  1438.           sprintf(pr_fmt,
  1439.               "\1\2--%s-- %s%s %s--%%s--%%s\1",
  1440. !             group_name,
  1441.               (mode & MM_DIGEST) ? "DIGEST" :
  1442.               (mode & MM_PREVIEW) ? "PREVIEW" : "LAST",
  1443.               (ah->flag & A_NEXT_SAME) ? "+next" : "",
  1444. ***************
  1445. *** 239,245 ****
  1446.       else
  1447.           sprintf(pr_fmt,
  1448.               "\1\2--%s-- %ld MORE%s %s--%%s--%%s\1",
  1449. !             current_group->group_name,
  1450.               n_selected,
  1451.               (ah->flag & A_NEXT_SAME) ? "+next" : "",
  1452.               novice ? "--help:?" : "");
  1453. --- 386,392 ----
  1454.       else
  1455.           sprintf(pr_fmt,
  1456.               "\1\2--%s-- %ld MORE%s %s--%%s--%%s\1",
  1457. !             group_name,
  1458.               n_selected,
  1459.               (ah->flag & A_NEXT_SAME) ? "+next" : "",
  1460.               novice ? "--help:?" : "");
  1461. ***************
  1462. *** 315,397 ****
  1463.   
  1464.       if (hdrline && screen_offset == 0) {
  1465.   
  1466. !         hdr_mode = 0;
  1467. !         while (*hdrline) {
  1468. !         if (*hdrline == '*') goto print_header;
  1469.   
  1470. !         if (*hdrline == '=') {
  1471. !             hdr_mode = 1;
  1472. !             hdrline++;
  1473. !             continue;
  1474. !         }
  1475. !         if (*hdrline == '_') {
  1476. !             hdr_mode = 2;
  1477. !             hdrline++;
  1478. !             continue;
  1479. !         }
  1480. !         for (hdef = header_defs; hdef->field; hdef++) {
  1481. !             if (hdef->field != *hdrline) continue;
  1482. !             if (in_digest) {
  1483. !             if (hdef->digest == NULL) break;
  1484. !             if ((lp = *(hdef->digest)) == NULL)
  1485.                   break;
  1486. -             } else
  1487. -             if ((lp = *(hdef->news)) == NULL)
  1488. -                 break;
  1489. -             if (*hdrline == 'n' || *hdrline == 'g')
  1490. -             if ((current_group->group_flag & G_MERGED) == 0 &&
  1491. -                 strchr(lp, ',') == NULL) break;
  1492. -             if (*hdrline == 'g' || *hdrline == 'G')
  1493. -             lp = current_group->group_name;
  1494. -             gotoxy(0, lno++);
  1495. -             printf("%s: ", hdef->text);
  1496. -             c = col = strlen(hdef->text) + 2;
  1497. -          split_header_line:
  1498. -             switch (hdr_mode) {
  1499. -              case 0:
  1500. -             break;
  1501. -              case 1:
  1502. -             highlight(1);
  1503. -             break;
  1504. -              case 2:
  1505. -             underline(1);
  1506. -             break;
  1507. -             }
  1508. -             while (*lp && c < Columns) {
  1509. -             if (isspace(*lp)) {
  1510. -                 while (lp[1] && isspace(lp[1])) lp++;
  1511. -                 if (wrap_headers > 0 &&
  1512. -                 (c + wrap_headers) >= Columns &&
  1513. -                 strlen(lp) >= wrap_headers) {
  1514. -                 lp++;
  1515. -                 break;
  1516. -                 }
  1517. -                 *lp = SP;
  1518.               }
  1519. !             putchar(*lp++);
  1520. !             c++;
  1521. !             }
  1522. !             switch (hdr_mode) {
  1523. !              case 0:
  1524. !             break;
  1525. !              case 1:
  1526. !             highlight(0);
  1527. !             break;
  1528. !              case 2:
  1529. !             underline(0);
  1530. !             break;
  1531.               }
  1532. !             if (*lp && wrap_headers >= 0) {
  1533. !             gotoxy(col, lno++);
  1534. !             c = col;
  1535. !             goto split_header_line;
  1536. !             }
  1537. !             break;
  1538.           }
  1539. -         hdr_mode = 0;
  1540. -         hdrline++;
  1541.           }
  1542.   
  1543.           hdrline = NULL;
  1544. --- 462,503 ----
  1545.   
  1546.       if (hdrline && screen_offset == 0) {
  1547.   
  1548. !         scan_header_fields(hdrline, ah);
  1549. !         while (next_header_field(&fname, &hdrline, &hdrattr)) {
  1550.   
  1551. !         if (fname == NULL) {
  1552. !             hdrline = --scan_codes;    /* this is a hack! */
  1553. !             goto print_header;
  1554. !         }
  1555. !         lp = hdrline;
  1556. !         gotoxy(0, lno++);
  1557. !         printf("%s: ", fname);
  1558. !         c = col = strlen(fname) + 2;
  1559. !          split_header_line:
  1560. !         if (hdrattr) CALL(hdrattr)(1);
  1561. !         while (*lp && c < Columns) {
  1562. !             if (isspace(*lp)) {
  1563. !             while (lp[1] && isspace(lp[1])) lp++;
  1564. !             if (wrap_headers > 0 &&
  1565. !                 (c + wrap_headers) >= Columns &&
  1566. !                 strlen(lp) >= wrap_headers) {
  1567. !                 lp++;
  1568.                   break;
  1569.               }
  1570. !             *lp = SP;
  1571.               }
  1572. !             putchar(*lp++);
  1573. !             c++;
  1574. !         }
  1575. !         if (hdrattr) CALL(hdrattr)(0);
  1576. !         if (*lp && wrap_headers >= 0) {
  1577. !             gotoxy(col, lno++);
  1578. !             c = col;
  1579. !             goto split_header_line;
  1580.           }
  1581.           }
  1582.   
  1583.           hdrline = NULL;
  1584. ***************
  1585. *** 417,422 ****
  1586. --- 523,529 ----
  1587.           extra_lines = print_lines - stop_line;
  1588.           print_lines = stop_line;
  1589.           underline_line = -1;
  1590. +         shade_overlap = 0;
  1591.       }
  1592.       stop_line = 0;
  1593.       } else
  1594. ***************
  1595. *** 621,626 ****
  1596. --- 728,734 ----
  1597.       if (overlap > 0) {
  1598.           underline_line = linenum - 1;
  1599.           linenum -= overlap + 1;
  1600. +         shade_overlap = mark_overlap_shading;
  1601.           goto next_page;
  1602.       }
  1603.       }
  1604. ***************
  1605. *** 647,652 ****
  1606. --- 755,767 ----
  1607.   
  1608.       /* now print the line */
  1609.   
  1610. +     shade_line = 0;
  1611. +     if ((shade_overlap > 0 && linenum <= underline_line) ||
  1612. +     (shade_overlap < 0 && linenum > underline_line)) {
  1613. +     if (match_redraw) goto no_print;
  1614. +     match_start = NULL;
  1615. +     shade_line = 1;
  1616. +     } else
  1617.       if (match_lines && underline_line != linenum &&
  1618.       regexec_cf(regular_expr, linebuf)) {
  1619.       match_start = regular_expr->startp[0];
  1620. ***************
  1621. *** 659,664 ****
  1622. --- 774,782 ----
  1623.       gotoxy(0, lno);
  1624.       if (!scroll_clear_page) clrline();
  1625.   
  1626. +     if (shade_line)
  1627. +     shadeline(1);
  1628. +     else
  1629.       if (mark_overlap && underline_line == linenum)
  1630.       if (!underline(1))
  1631.           fake_underline = 1;
  1632. ***************
  1633. *** 695,700 ****
  1634. --- 813,825 ----
  1635.   
  1636.       if (match_start) highlight(0);
  1637.   
  1638. +     if (shade_line) {
  1639. +     shadeline(0);
  1640. +     if (shade_overlap > 0 && underline_line == linenum) {
  1641. +         underline_line = -1;
  1642. +         shade_overlap = 0;
  1643. +     }
  1644. +     } else
  1645.       if (mark_overlap && underline_line == linenum) {
  1646.       while (lp - linebuf < 10) {
  1647.           putchar(fake_underline ? '_' : ' ');
  1648. ***************
  1649. *** 710,715 ****
  1650. --- 835,845 ----
  1651.       ++lno;
  1652.       if (--print_lines > 0 && s_keyboard == 0 && form_feed == 0) goto next_line;
  1653.   
  1654. +     if (shade_overlap) {
  1655. +     underline_line = -1;
  1656. +     shade_overlap = 0;
  1657. +     }
  1658.       if (!eof && linenum >= maxline) {
  1659.       if (ignore_nl) {
  1660.           c = getc(art);
  1661. ***************
  1662. *** 753,765 ****
  1663.   
  1664.       if (flush_typeahead) flush_input();
  1665.   
  1666.       if ((c = get_c()) & GETC_COMMAND)
  1667.       c &= ~GETC_COMMAND;
  1668.       else
  1669. !     c = more_key_map[c];
  1670.   
  1671.       if (s_hangup) c = K_QUIT;
  1672.   
  1673.       if (any_message && c != K_LAST_MESSAGE) clrmsg(0);
  1674.   
  1675.       if (c & K_MACRO) {
  1676. --- 883,904 ----
  1677.   
  1678.       if (flush_typeahead) flush_input();
  1679.   
  1680. +     key_map = more_key_map;
  1681. +  prefix_key:    
  1682.       if ((c = get_c()) & GETC_COMMAND)
  1683.       c &= ~GETC_COMMAND;
  1684.       else
  1685. !     c = key_map[cur_key = c];
  1686.   
  1687.       if (s_hangup) c = K_QUIT;
  1688.   
  1689. +     if (c & K_PREFIX_KEY) {
  1690. +     key_map = keymaps[c & ~K_PREFIX_KEY].km_map;
  1691. +     if (echo_prefix_key) msg("%s", key_name(cur_key));
  1692. +     goto prefix_key;
  1693. +     }
  1694.       if (any_message && c != K_LAST_MESSAGE) clrmsg(0);
  1695.   
  1696.       if (c & K_MACRO) {
  1697. ***************
  1698. *** 797,802 ****
  1699. --- 936,942 ----
  1700.           if (linenum > overlap) {
  1701.           underline_line = linenum;
  1702.           linenum -= overlap;
  1703. +         shade_overlap = mark_overlap_shading;
  1704.           }
  1705.       }
  1706.       goto next_page;
  1707. ***************
  1708. *** 1012,1017 ****
  1709. --- 1152,1158 ----
  1710.       if (topline <= 1) goto Prompt;
  1711.       linenum = topline - window_lines + overlap; /* not perfect after FF */
  1712.       underline_line = topline;
  1713. +     shade_overlap = -mark_overlap_shading;
  1714.       if (linenum < 1) linenum = 1;
  1715.       goto next_page;
  1716.   
  1717. *** ./LAST/nn.c    Mon Jun 25 15:46:50 1990
  1718. --- nn.c    Tue Jun 26 11:25:28 1990
  1719. ***************
  1720. *** 557,563 ****
  1721.       mallopt(M_NLBLKS, MALLOC_FASTBLOCKS);
  1722.   #endif
  1723.   #ifdef MALLOC_GRAIN
  1724. !     mallopt(M_GRAIN, MALLOC_GRAIN));
  1725.   #endif
  1726.   #endif
  1727.   
  1728. --- 557,563 ----
  1729.       mallopt(M_NLBLKS, MALLOC_FASTBLOCKS);
  1730.   #endif
  1731.   #ifdef MALLOC_GRAIN
  1732. !     mallopt(M_GRAIN, MALLOC_GRAIN);
  1733.   #endif
  1734.   #endif
  1735.   
  1736. *** ./LAST/nntp.c    Tue Jun 12 11:47:00 1990
  1737. --- nntp.c    Thu Jul  5 12:57:33 1990
  1738. ***************
  1739. *** 788,793 ****
  1740. --- 788,838 ----
  1741.   }
  1742.   
  1743.   /*
  1744. +  * nntp_get_newsgroups:  get a copy of the newsgroups file.
  1745. +  *
  1746. +  *    Use the "LIST NEWSGROUPS" command to get the newsgroup descriptions.
  1747. +  *    Based on code from: olson%anchor.esd@sgi.com (Dave Olson)
  1748. +  */
  1749. + FILE *nntp_get_newsgroups()
  1750. + {
  1751. +     char *new_name;
  1752. +     FILE *new = NULL;
  1753. +     int n;
  1754. +     new_name = mktemp(relative(tmp_directory, "nngrXXXXXX"));
  1755. +     new = open_file(new_name, OPEN_CREATE_RW|OPEN_UNLINK);
  1756. +     if (new == NULL) return NULL;
  1757. +  again:
  1758. +     if (!is_connected && connect_server() < 0) goto err;
  1759. +     switch (n = ask_server("LIST NEWSGROUPS")) {
  1760. +      case OK_GROUPS:
  1761. +     if (copy_text(new) == 0) {
  1762. +         if (fflush(new) != EOF) break;
  1763. +         fclose(new);
  1764. +     }
  1765. +     if (!nntp_failed) {
  1766. +         log_entry('N', "LIST NEWSGROUPS empty");
  1767. +         nntp_failed = 1;
  1768. +     }
  1769. +     return NULL;
  1770. +      default:
  1771. +     if (try_again) goto again; /* Handle nntp server timeouts */
  1772. +     log_entry('N', "LIST NEWSGROUPS response: %d", n);
  1773. +     goto err;
  1774. +     }
  1775. +     rewind(new);
  1776. +     return new;
  1777. +  err:
  1778. +     fclose(new);
  1779. +     return NULL;
  1780. + }
  1781. + /*
  1782.    * nntp_get_article_list: get list of all article numbers in group
  1783.    *
  1784.    *     Sends XHDR command to the server, and parses the following
  1785. ***************
  1786. *** 834,839 ****
  1787. --- 879,885 ----
  1788.        default:
  1789.           if (try_again) goto again; /* Handle nntp server timeouts */
  1790.           log_entry('N', "LISTGROUP response: %d", n);
  1791. +         return NULL;
  1792.        case ERR_COMMAND:
  1793.           try_listgroup = 0;
  1794.           goto again;    /* error may have closed down server connection */
  1795. ***************
  1796. *** 857,862 ****
  1797. --- 903,909 ----
  1798.        default:
  1799.           if (try_again) goto again; /* Handle nntp server timeouts */
  1800.           log_entry('N', "XHDR response: %d", n);
  1801. +         return NULL;
  1802.        case ERR_COMMAND:
  1803.           nntp_failed = 2;
  1804.           return NULL;
  1805. *** ./LAST/patchlevel.h    Mon Jun 25 15:46:51 1990
  1806. --- patchlevel.h    Mon Jul  9 14:51:13 1990
  1807. ***************
  1808. *** 17,23 ****
  1809.    *    1990-05-29: Patch #4 (6.4.4) - HIGH
  1810.    *    1990-06-11: Patch #5 (6.4.5) - MEDIUM
  1811.    *    1990-06-25: Patch #6 (6.4.6) - MEDIUM
  1812.    */
  1813.   
  1814. ! #define PATCHLEVEL 6
  1815.   
  1816. --- 17,24 ----
  1817.    *    1990-05-29: Patch #4 (6.4.4) - HIGH
  1818.    *    1990-06-11: Patch #5 (6.4.5) - MEDIUM
  1819.    *    1990-06-25: Patch #6 (6.4.6) - MEDIUM
  1820. +  *    1990-07-09: Patch #7 (6.4.7) - LOW
  1821.    */
  1822.   
  1823. ! #define PATCHLEVEL 7
  1824.   
  1825. *** ./LAST/proto.c    Tue May 29 18:36:37 1990
  1826. --- proto.c    Thu Jul  5 23:45:04 1990
  1827. ***************
  1828. *** 10,15 ****
  1829. --- 10,21 ----
  1830.   #include <pwd.h>
  1831.   #include "proto.h"
  1832.   
  1833. + #ifndef ACCOUNTING
  1834. + #ifdef AUTHORIZE
  1835. + #define ACCOUNTING
  1836. + #endif
  1837. + #endif
  1838.   import char *master_directory, *db_directory;
  1839.   
  1840.   /*
  1841. *** ./LAST/save.c    Mon Jun 25 15:46:51 1990
  1842. --- save.c    Fri Jul  6 00:43:49 1990
  1843. ***************
  1844. *** 16,21 ****
  1845. --- 16,22 ----
  1846.   export int suggest_save_file = 1;
  1847.   export char *unshar_header_file = "Unshar.Headers";
  1848.   export int  use_mail_folders = 0;
  1849. + export int  use_path_in_from = 0;
  1850.   export int  use_mmdf_folders = 0;
  1851.   export int  save_report = 1;
  1852.   export int  quick_save = 0;
  1853. ***************
  1854. *** 22,27 ****
  1855. --- 23,32 ----
  1856.   export int  conf_append = 0;
  1857.   export int  conf_create = 1;
  1858.   
  1859. + export char *print_header_lines = "FDGS";
  1860. + export char *save_header_lines = "FDNS";
  1861. + static char *short_header_lines;
  1862.   export char *save_counter_format = "%d";    /* format of save counter */
  1863.   export int  save_counter_offset = 0;
  1864.   
  1865. ***************
  1866. *** 67,75 ****
  1867.   
  1868.   static int open_mode[] = {
  1869.       SKIP_HEADER,
  1870. !     FILL_NEWS_HEADER | SKIP_HEADER,
  1871.       0,
  1872. !     FILL_DIGEST_HEADER | SKIP_HEADER
  1873.   };
  1874.   
  1875.   static FILE *save_file;            /* output stream for saved files */
  1876. --- 72,80 ----
  1877.   
  1878.   static int open_mode[] = {
  1879.       SKIP_HEADER,
  1880. !     FILL_NEWS_HEADER | SKIP_HEADER | GET_ALL_FIELDS,
  1881.       0,
  1882. !     FILL_NEWS_HEADER | FILL_DIGEST_HEADER | SKIP_HEADER | GET_ALL_FIELDS
  1883.   };
  1884.   
  1885.   static FILE *save_file;            /* output stream for saved files */
  1886. ***************
  1887. *** 155,160 ****
  1888. --- 160,166 ----
  1889.       char *ckdir_path();
  1890.   
  1891.       uniq_counter = 0;
  1892. +     short_header_lines = save_header_lines;
  1893.   
  1894.       switch (command) {
  1895.   
  1896. ***************
  1897. *** 297,302 ****
  1898. --- 303,309 ----
  1899.           print_header_type = NO_HEADER;
  1900.       }
  1901.   
  1902. +     short_header_lines = print_header_lines;
  1903.       save_mode = print_header_type | IS_PIPE;
  1904.       
  1905.       if (!shell_restrictions && edit_print_command) {
  1906. ***************
  1907. *** 387,392 ****
  1908. --- 394,400 ----
  1909.       register FILE *art;
  1910.       register c, lcount, mode;
  1911.       news_header_buffer hdrbuf;
  1912. +     news_header_buffer dghdrbuf;
  1913.       int was_raw = 0, set_visual = 0;
  1914.       char copybuf[FILENAME * 4], uniqbuf[FILENAME];
  1915.       flag_type st_flag = A_ST_FILED;
  1916. ***************
  1917. *** 398,404 ****
  1918.       if (mode == SHORT_HEADER && ah->flag & A_DIGEST)
  1919.       mode = SHORT_HEADER_DG;
  1920.   
  1921. !     art = open_news_article(ah, open_mode[mode], hdrbuf, (char *)NULL);
  1922.       if (art == NULL) {
  1923.       msg("Cannot read %s", group_path_name);
  1924.       return 0;
  1925. --- 406,416 ----
  1926.       if (mode == SHORT_HEADER && ah->flag & A_DIGEST)
  1927.       mode = SHORT_HEADER_DG;
  1928.   
  1929. !     c = open_mode[mode];
  1930. !     if (use_mail_folders && use_path_in_from && (c & FILL_NEWS_HEADER) == 0)
  1931. !     c |= FILL_NEWS_HEADER | GET_ALL_FIELDS;
  1932. !     art = open_news_article(ah, c, hdrbuf, dghdrbuf);
  1933.       if (art == NULL) {
  1934.       msg("Cannot read %s", group_path_name);
  1935.       return 0;
  1936. ***************
  1937. *** 494,515 ****
  1938.           putc(c, save_file);
  1939.       }
  1940.       } else
  1941. !     if (mode == SHORT_HEADER) {
  1942. !     if (news.ng_from)
  1943. !         fprintf(save_file, "From: %s\n", news.ng_from);
  1944. !     if (news.ng_date)
  1945. !         fprintf(save_file, "Date: %s\n", news.ng_date);
  1946. !     if (news.ng_subj)
  1947. !         fprintf(save_file, "Subject: %s\n", news.ng_subj);
  1948. !     fputc(NL, save_file);
  1949. !     } else
  1950. !     if (mode == SHORT_HEADER_DG) {
  1951. !     if (digest.dg_from)
  1952. !         fprintf(save_file, "From: %s\n", digest.dg_from);
  1953. !     if (digest.dg_date)
  1954. !         fprintf(save_file, "Date: %s\n", digest.dg_date);
  1955. !     if (digest.dg_subj)
  1956. !         fprintf(save_file, "Subject: %s\n", digest.dg_subj);
  1957.       fputc(NL, save_file);
  1958.       }
  1959.   
  1960. --- 506,518 ----
  1961.           putc(c, save_file);
  1962.       }
  1963.       } else
  1964. !     if (mode == SHORT_HEADER || mode == SHORT_HEADER_DG) {
  1965. !     char *name, *val;
  1966. !     scan_header_fields(short_header_lines, ah->flag & A_DIGEST);
  1967. !     while (next_header_field(&name, &val, (fct_type *)NULL)) {
  1968. !         if (name == NULL) continue;
  1969. !         fprintf(save_file, "%s: %s\n", name, val);
  1970. !     }
  1971.       fputc(NL, save_file);
  1972.       }
  1973.   
  1974. ***************
  1975. *** 653,658 ****
  1976. --- 656,662 ----
  1977.       if (use_mail_folders) {
  1978.       now = cur_time();
  1979.       fprintf(f, "From %s %s",
  1980. +         (use_path_in_from && news.ng_path) ? news.ng_path :
  1981.           current_group->group_name, ctime(&now));
  1982.       return 1;
  1983.       }
  1984. *** ./LAST/variable.c    Mon Jun 25 15:46:52 1990
  1985. --- variable.c    Thu Jul  5 19:54:29 1990
  1986. ***************
  1987. *** 34,41 ****
  1988. --- 34,45 ----
  1989.       *pager,
  1990.       patch_command[],
  1991.       printer[],
  1992. +     *print_header_lines,
  1993.       *response_dflt_answer,
  1994.       *save_counter_format,
  1995. +     *save_header_lines,
  1996. +     *shade_on_attr,
  1997. +     *shade_off_attr,
  1998.       *spell_checker,
  1999.       *trusted_escapes,
  2000.       unshar_command[],
  2001. ***************
  2002. *** 64,69 ****
  2003. --- 68,74 ----
  2004.       dont_sort_articles,
  2005.       dont_sort_folders,
  2006.       dont_split_digests,
  2007. +     echo_prefix_key,
  2008.       edit_patch_command,
  2009.       edit_print_command,
  2010.       edit_unshar_command,
  2011. ***************
  2012. *** 83,88 ****
  2013. --- 88,94 ----
  2014.       macro_debug,
  2015.       mailer_pipe_input,
  2016.       mark_overlap,
  2017. +     mark_overlap_shading,
  2018.       match_parts_equal,
  2019.       monitor_mode,
  2020.       new_read_prompt,
  2021. ***************
  2022. *** 109,114 ****
  2023. --- 115,121 ----
  2024.       tidy_newsrc,
  2025.       use_mail_folders,
  2026.       use_mmdf_folders,
  2027. +     use_path_in_from,
  2028.       use_selections,
  2029.       use_visible_bell;
  2030.   
  2031. ***************
  2032. *** 233,238 ****
  2033. --- 240,246 ----
  2034.       "default-kill-select",    INT 0,        (char **)&dflt_kill_select,
  2035.       "default-save-file",    STR 3,        (char **)&default_save_file,
  2036.       "delay-redraw",        BOOL 0,        (char **)&delay_redraw,
  2037. +     "echo-prefix-key",         BOOL 0,        (char **)&echo_prefix_key,
  2038.       "edit-patch-command",     BOOL 0,        (char **)&edit_patch_command,
  2039.       "edit-print-command",     BOOL 0,        (char **)&edit_print_command,
  2040.       "edit-response-check",     BOOL 0,        (char **)&empty_answer_check,
  2041. ***************
  2042. *** 273,278 ****
  2043. --- 281,287 ----
  2044.       "mailer",            STR 0,        (char **)&mailer_program,
  2045.       "mailer-pipe-input",    BOOL 0,        (char **)&mailer_pipe_input,
  2046.       "mark-overlap",        BOOL 0,        (char **)&mark_overlap,
  2047. +     "mark-overlap-shading",    BOOL 0,        (char **)&mark_overlap_shading,
  2048.       "marked-by-next-group",    INT 0,        (char **)&mark_next_group,
  2049.       "marked-by-read-return",    INT 0,        (char **)&mark_read_return,
  2050.       "marked-by-read-skip",    INT 0,        (char **)&mark_read_skip,
  2051. ***************
  2052. *** 299,304 ****
  2053. --- 308,314 ----
  2054.       "patch-command",        STR SAFE 1,    (char **)patch_command,
  2055.       "preview-continuation",     INT 0,        (char **)&preview_continuation,
  2056.       "preview-mark-read",    BOOL 0,        (char **)&preview_mark_read,
  2057. +     "print-header-lines",    STR 0,        (char **)&print_header_lines,
  2058.       "print-header-type",    INT 0,        (char **)&print_header_type,
  2059.       "printer",            STR SAFE 1,    (char **)printer,
  2060.       "query-signature",        BOOL 0,        (char **)&query_signature,
  2061. ***************
  2062. *** 316,325 ****
  2063. --- 326,338 ----
  2064.       "retry-on-error",        INT 0,        (char **)&retry_on_error,
  2065.       "save-counter",        STR 3,        (char **)&save_counter_format,
  2066.       "save-counter-offset",    INT 0,        (char **)&save_counter_offset,
  2067. +     "save-header-lines",    STR 0,        (char **)&save_header_lines,
  2068.       "save-report",        BOOL 0,        (char **)&save_report,
  2069.       "scroll-clear-page",    BOOL 0,        (char **)&scroll_clear_page,
  2070.       "select-leave-next",    BOOL 0,        (char **)&select_leave_next,
  2071.       "select-on-sender",        BOOL 0,        (char **)&select_on_sender,
  2072. +     "shading-off",        STR 0,        (char **)&shade_off_attr,
  2073. +     "shading-on",        STR 0,        (char **)&shade_on_attr,
  2074.       "shell",            STR SAFE 0,    (char **)&user_shell,
  2075.       "shell-restrictions",     BOOL INIT 0,    (char **)&shell_restrictions,
  2076.       "show-purpose-mode",    INT 0,        (char **)&show_purpose_mode,
  2077. ***************
  2078. *** 342,347 ****
  2079. --- 355,361 ----
  2080.       "unshar-header-file",    STR 0,        (char **)&unshar_header_file,
  2081.       "unsubscribe-mark-read",    BOOL 4,        (char **)&keep_unsub_long,
  2082.       "update-frequency",        INT 0,        (char **)&newsrc_update_freq,
  2083. +     "use-path-in-from",        BOOL 0,        (char **)&use_path_in_from,
  2084.       "use-selections",         BOOL 0,        (char **)&use_selections,
  2085.       "visible-bell",         BOOL 0,        (char **)&use_visible_bell,
  2086.       "window",            INT 1,        (char **)&preview_window,
  2087.